package com.snowfeel.sfmall.oss.init;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.snowfeel.oss.config.OssProperties;
import com.snowfeel.oss.constants.OssConstants;
import com.snowfeel.oss.exception.ErrorCode;
import com.snowfeel.oss.exception.OssException;
import com.snowfeel.oss.storage.OssTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.net.HttpCookie;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Minio初始化
 *
 * @author: guomenghuai
 * @date: 2024/4/17 11:34
 */
@Slf4j
@Component
public class MinioInit implements CommandLineRunner {

    /**
     * 登录地址
     */
    private final static String LOGIN_URL = "/api/v1/login";

    /**
     * 创建密钥地址
     */
    private final static String CREATE_KEY_URL = "/api/v1/service-account-credentials";

    @Autowired
    private OssProperties ossProperties;

    @Autowired
    private OssTemplate ossTemplate;

    /**
     * 桶策略模板
     */
    private final static String POLICY_TEMPLDATE = "{\n"
            + "  \"Version\": \"2012-10-17\",\n"
            + "  \"Statement\": [\n"
            + "    {\n"
            + "      \"Effect\": \"Allow\",\n"
            + "      \"Principal\": {\n"
            + "        \"AWS\": [\n"
            + "          \"*\"\n"
            + "        ]\n"
            + "      },\n"
            + "      \"Action\": [\n"
            + "        \"s3:GetBucketLocation\",\n"
            + "        \"s3:ListBucket\"\n"
            + "      ],\n"
            + "      \"Resource\": [\n"
            + "        \"arn:aws:s3:::BUCKET_NAME\"\n"
            + "      ]\n"
            + "    },\n"
            + "    {\n"
            + "      \"Effect\": \"Allow\",\n"
            + "      \"Principal\": {\n"
            + "        \"AWS\": [\n"
            + "          \"*\"\n"
            + "        ]\n"
            + "      },\n"
            + "      \"Action\": [\n"
            + "        \"s3:GetObject\"\n"
            + "      ],\n"
            + "      \"Resource\": [\n"
            + "        \"arn:aws:s3:::BUCKET_NAME/*\"\n"
            + "      ]\n"
            + "    },\n"
            + "    {\n"
            + "      \"Effect\": \"Deny\",\n"
            + "      \"Principal\": {\n"
            + "        \"AWS\": [\n"
            + "          \"*\"\n"
            + "        ]\n"
            + "      },\n"
            + "      \"Action\": [\n"
            + "        \"s3:GetObject\"\n"
            + "      ],\n"
            + "      \"Resource\": [\n"
            + "        \"arn:aws:s3:::BUCKET_NAME/credentials/*\",\n"
            + "        \"arn:aws:s3:::BUCKET_NAME/privacy/*\",\n"
            + "        \"arn:aws:s3:::BUCKET_NAME/report/*\"\n"
            + "      ]\n"
            + "    }\n"
            + "  ]\n"
            + "}";

    @Override
    public void run(String... args) throws Exception {
        if (OssConstants.MINIO.equals(ossProperties.getPlatform())) {
            //登录minio console获取cookies
            List<HttpCookie> cookies = Lists.newArrayList();
            try {
                Map<String, Object> loginBody = Maps.newHashMap();
                loginBody.put("accessKey", ossProperties.getMinioUserName());
                loginBody.put("secretKey", ossProperties.getMinioUserPassword());
                HttpResponse logRes = HttpRequest
                        .post(ossProperties.getMinioConsoleEndpoint() + LOGIN_URL)
                        .body(JSON.toJSONString(loginBody)).execute();
                if (HttpStatus.HTTP_OK != logRes.getStatus() && HttpStatus.HTTP_NO_CONTENT != logRes
                        .getStatus()) {
                    Map<String, Object> resBody = JSON.parseObject(logRes.body(), Map.class);
                    String errorMessage = "Bad Request";
                    if (Objects.nonNull(resBody) && Objects
                            .nonNull(resBody.get("detailedMessage"))) {
                        errorMessage = resBody.get("detailedMessage").toString();
                    }
                    throw new OssException(ErrorCode.UNKNOWN, errorMessage);
                }
                cookies = logRes.getCookies();
            } catch (Exception ex) {
                log.error("登录minio console失败", ex);
            }
            if (CollectionUtils.isNotEmpty(cookies)) {
                //创建密钥
                try {
                    Map<String, Object> createKeyBody = Maps.newHashMap();
                    createKeyBody.put("accessKey", ossProperties.getAccessKey());
                    createKeyBody.put("secretKey", ossProperties.getSecretKey());
                    HttpResponse createKeyRes = HttpRequest
                            .post(ossProperties.getMinioConsoleEndpoint() + CREATE_KEY_URL)
                            .cookie(cookies).body(JSON.toJSONString(createKeyBody))
                            .execute();
                    if (HttpStatus.HTTP_OK != createKeyRes.getStatus()
                            && HttpStatus.HTTP_CREATED != createKeyRes.getStatus()) {
                        Map<String, Object> resBody = JSON.parseObject(createKeyRes.body(), Map.class);
                        String errorMessage = "Bad Request";
                        if (Objects.nonNull(resBody) && Objects
                                .nonNull(resBody.get("detailedMessage"))) {
                            errorMessage = resBody.get("detailedMessage").toString();
                        }
                        throw new OssException(ErrorCode.UNKNOWN, errorMessage);
                    }
                } catch (Exception ex) {
                    log.error("创建minio密钥失败", ex);
                }
                //创建桶和设置桶策略
                boolean bucketExists = ossTemplate.bucketExists(ossProperties.getBucketName());
                if (!bucketExists) {
                    ossTemplate.createBucket(ossProperties.getBucketName());
                }
                ossTemplate.setBucketPolicy(ossProperties.getBucketName(),
                        POLICY_TEMPLDATE.replaceAll("BUCKET_NAME", ossProperties.getBucketName()));
                log.info("Minio初始化成功");
            }
        }
    }
}
